package com.googlecode.bizyap.impl.tomcat.realm;

import java.lang.reflect.Method;
import java.security.Principal;
import java.util.Set;

import com.googlecode.bizyap.core.Application;
import com.googlecode.bizyap.core.SSOAuthProvider;
import com.googlecode.bizyap.core.SSOContext;
import com.googlecode.bizyap.core.UserPrincipal;
import com.googlecode.bizyap.core.logging.Logger;
import com.googlecode.bizyap.core.logging.LoggerFactory;
import com.googlecode.bizyap.impl.tomcat.Globals;

public final class SSORealmHelper {
	
	private static final Logger log = LoggerFactory.getLogger(SSORealmHelper.class);
	
	public static Principal getPrincipal(String username) {
		Application app = SSOContext.getApplication();
		UserPrincipal user = UserPrincipal.createInstance(username);
		String authClassName = app.getAuthorizationClassName();
		Class/*<SSOAuthProvider>*/ authClass = null;

		if(authClassName!=null && authClassName.length()>0){
			try {
				// this is web-context class loader
				ClassLoader cl = Thread.currentThread().getContextClassLoader();
				authClass = cl.loadClass(authClassName);
			}
			catch (Exception e) {
				log.error("while loading auth class: " + authClassName, e);
			}
		}

		Object/*SSOAuthProvider*/ auth = null;
		if(authClass!=null){
			try {
				auth = authClass.newInstance();
			} catch (Exception e) {
				log.error("while instantiating authorize object from class (class must have a public empty constructor): " + authClass, e);
			}
		}

		if(auth!=null){
			try {
				Principal appUser = null;
				Set<Principal> appRoles = null;

				// if SSOAuthProvider interface is bundled with web application,
				// then (auth instanceof SSOAuthProvider) will return false.
				// because in that case, SSOAuthProvider class here is loaded via both server common class loader
				// and web-app class loader.
				// And auth object is intstance of SSOAuthProvider that loaded by web-app class loader,
				// not SSOAuthProvider in classpath of server.

				if(auth instanceof SSOAuthProvider){
					if(log.isDebugEnabled())log.debug("-auth- object is instance of SSOAuthProvider... ");

					SSOAuthProvider ssoAuth = (SSOAuthProvider)auth;
					appUser = ssoAuth.authenticate(user.getName(), user.getDomain());
					appRoles = ssoAuth.authorize(appUser);
				}
				else {
					if(log.isDebugEnabled())log.debug("using reflection to invoke -auth- object methods.. ");

					Method authenticate = authClass.getMethod(Globals.AUTHENTICATE_METHOD, Globals.AUTHENTICATE_METHOD_PARAM);
					appUser = (Principal)authenticate.invoke(auth, user.getName(), user.getDomain());

					Method authorize = authClass.getMethod(Globals.AUTHORIZE_METHOD, Globals.AUTHORIZE_METHOD_PARAM);
					appRoles = (Set<Principal>)authorize.invoke(auth, appUser);
				}

				user.setAppUser(appUser);
				user.setAppRoles(appRoles);
			} catch (Exception e) {
				log.error("while finding or invoking auth methods: " + authClass, e);
			}
		}
		return user;
	}

	public static boolean hasRole(Principal principal, String role) {
		if(!(principal instanceof UserPrincipal)){
			return false;
		}

		UserPrincipal user = (UserPrincipal)principal;
		Set<Principal> roles = user.getAppRoles();

		for (Principal appRole : roles) {
			if(appRole.getName().equals(role)){
				return true;
			}
		}
		return false;
    }
	
	
	private SSORealmHelper() {}
}
